package city.spring.modules.checkinfee.service.impl;

import city.spring.modules.checkinfee.entity.CheckinfeeEntity;
import city.spring.modules.checkinfee.repository.CheckinfeeRepository;
import city.spring.modules.checkinfee.service.CheckinfeeService;
import city.spring.modules.checkinfee.vo.CheckinfeeVO;
import city.spring.modules.checkinfeeDetail.repository.CheckinfeeDetailRepository;
import city.spring.modules.checkinfeeDetail.vo.CheckinfeeDetailVO;
import city.spring.modules.expense.repository.ExpenseRecordRepository;
import city.spring.modules.oldman.entity.OldmanInfoEntity;
import city.spring.modules.oldman.service.OldmanInfoService;
import city.spring.modules.reception.entity.CheckInRecordEntity;
import city.spring.modules.reception.repository.CheckInRecordRepository;
import city.spring.modules.system.entity.UserEntity;
import city.spring.modules.system.service.UserService;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.ibatis.annotations.Param;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.security.Principal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Service：入院收费
 *
 * @author 谢金婷
 * @date 2020-08-27 10:19:04
 */
@CacheConfig(cacheNames = {CheckinfeeServiceImpl.CACHE_NAME})
@Transactional(rollbackFor = Exception.class)
@Service
public class CheckinfeeServiceImpl extends ServiceImpl<CheckinfeeRepository, CheckinfeeEntity> implements CheckinfeeService {

    private final CheckinfeeRepository checkinfeeRepository;
    private final UserService userService;
    private final OldmanInfoService oldmanInfoService;
    private final CheckinfeeDetailRepository checkinfeeDetailRepository;
    private final CheckInRecordRepository checkInRecordRepository;

    public CheckinfeeServiceImpl(UserService userService, OldmanInfoService oldmanInfoService, CheckinfeeDetailRepository checkinfeeDetailRepository, ExpenseRecordRepository expenseRecordRepository, CheckinfeeRepository checkinfeeRepository, CheckinfeeDetailRepository checkinfeeDetailRepository1, CheckInRecordRepository checkInRecordRepository) {
        this.userService = userService;
        this.oldmanInfoService = oldmanInfoService;
        this.checkinfeeRepository = checkinfeeRepository;
        this.checkinfeeDetailRepository = checkinfeeDetailRepository1;
        this.checkInRecordRepository = checkInRecordRepository;
    }

    @Override
    public void saveCheckinfee(CheckinfeeEntity entity) {
        if (!save(entity)) {
            throw new RuntimeException("保存信息失败");
        }
    }

    @Override
    public void updateCheckinfee(CheckinfeeEntity entity) {
        // 使用 updateById(entity); 修改数据时，将会修改 entity 对象中所有非null数据，如果某个字段为null，将会忽略该字段的修改
        if (!updateById(entity)) {
            throw new RuntimeException("修改信息失败");
        }
    }

    @Override
    public void deleteCheckinfee(String primaryKey) {
        removeById(primaryKey);
    }

    @Override
    public void deleteCheckinfee(List<String> primaryKeys) {
        removeByIds(primaryKeys);
    }

    @Override
    public IPage<CheckinfeeVO> listPage(Page<? extends CheckinfeeEntity> page, Wrapper<? extends CheckinfeeEntity> wrapper) {
        return baseMapper.listPage(page, wrapper);
    }

    @Override
    public CheckinfeeEntity getCheckfeeByolamanId(String oldmanId) {
        return checkinfeeRepository.getCheckfeeByolamanId(oldmanId);
    }

    @Override
    public IPage<CheckinfeeVO> monthlyFeelist(Page<? extends CheckinfeeEntity> page, Wrapper<? extends CheckinfeeEntity> wrapper) {
        return baseMapper.monthlyFeelist(page, wrapper);
    }

    @Override
    public List<CheckinfeeVO> monthlyFeelist2(Wrapper<? extends CheckinfeeEntity> wrapper2) {
        return baseMapper.monthlyFeelist2(wrapper2);
    }

    @Override
    public CheckinfeeVO monthlyFeelist3(Wrapper<? extends CheckinfeeEntity> wrapper2) {
        return baseMapper.monthlyFeelist3(wrapper2);
    }

    @Override
    public CheckinfeeEntity getCheckinfeeWithCategory(String oldmanId) {
        return checkinfeeRepository.getCheckinfeeWithCategory(oldmanId);
    }

    @Override
    public CheckinfeeEntity getLatestPayRecord(String personId) {
        return checkinfeeRepository.getLatestPayRecord(personId);
    }

    @Override
    public CheckinfeeEntity saveMonthfee(CheckinfeeEntity entity, @NotNull Principal user) {
        UserEntity userEntity = userService.getUserByIdOrAccount(user.getName());
        entity.setUserId(userEntity.getId()); // // 经办人
        OldmanInfoEntity oldman = oldmanInfoService.getById(entity.getOldmanId());
        entity.setType(oldman.getStatus()); // 入住状态 正式、试入住
        entity.setCategory(2); // 2:月度缴费
        entity.setStatus(1); // 1：缴费
        entity.setCertificate(oldman.getCertificate());
        String nowTimestr = new SimpleDateFormat("yyyyMMdd").format(new Date());
        entity.setMark(nowTimestr);
        if (!save(entity)) {
            throw new RuntimeException("保存信息失败");
        }
        return entity;
    }

    @Override
    public void addMonthPayRecords(List<String> oldids) {

    }

    @Override
    public IPage<CheckinfeeVO> monthPayRecords(Page<? extends CheckinfeeEntity> page, @Param(Constants.WRAPPER) Wrapper<? extends CheckinfeeEntity> wrapper) {
        return checkinfeeRepository.monthPayRecords(page, wrapper);
    }

    @Override
    public CheckinfeeVO monthPayPrintInfo(String feeid) {
        return checkinfeeRepository.monthPayPrintInfo(feeid);
    }

    @Override
    public List<CheckinfeeVO> settlementPayRecords(String personId, Date leaveDate) {
        // 1、根据老人ID 获取押金金额
        CheckinfeeDetailVO checkinfeeDetailVO = checkinfeeDetailRepository.getDepositAndBalance(personId);
        BigDecimal deposts = checkinfeeDetailVO.getDepositMount();
        // 2、设传入参数  退住日期格式化yyyyMM，并转为int，如202012
        String leave1 = new SimpleDateFormat("yyyyMM").format(leaveDate);
        String leave2 = new SimpleDateFormat("yyyyMMdd").format(leaveDate);
        // 退住年月 202011
        int leaveMonth = Integer.parseInt(leave1);
        // 退住当月 实际交费天数 20201115 取模，15天
        int taldays = Integer.parseInt(leave2) % 100;
        // 3、 取入住日期-退住日期之间的已交费用记录
        List<CheckinfeeVO> records = checkinfeeRepository.settlementPayRecords(personId, leaveMonth, taldays);
        // 4、循环判断 费用记录是入院交费1，则该条记录扣除押金金额
        for (int i = 0; i < records.size(); i++) {
            if (records.get(i).getCategory() == 1) {
                records.get(i).setDiscountedcost(records.get(i).getDiscountedcost().subtract(deposts));
            }
        }
        return records;
    }

    @Override
    public Object[] isAlreadyPayBeforeLeaveMonth(String personId, Date leaveDate) {
        // list 已经交费的月份yyyymm int类型
        List<Integer> alreadyPayMonths = checkinfeeRepository.isAlreadyPayBeforeLeaveMonth(personId);
        // 退住日期格式化yyyyMM，并转为int，如202012
        String leave = new SimpleDateFormat("yyyyMM").format(leaveDate);
        int leaveMonth = Integer.parseInt(leave);
        // 退住日期的月份
        int singleDigitt = leaveMonth % 10;
        int singleDigitt2 = leaveMonth % 100;
        // 退住日期 前一个月是多少  退住日期的月份为1，如202101，前一个月为202101-89=202012，不是1的月份 -1
        int previousMonth = 0;
        // 01 11 月
        if (singleDigitt == 1 && singleDigitt2 != 11) {
            previousMonth = leaveMonth - 89;
        } else {
            previousMonth = leaveMonth - 1;
        }
        // 返回的结果： 是否需要先去交费 0：不需要去补交费 1：需要，交到哪个月
        Object[] objs = new Object[3];
        // 循环遍历看有没退住日期的前一个月交费记录，有就不用去补交费，没有就需要去
        for (int i = 0; i < alreadyPayMonths.size(); i++) {
            if (alreadyPayMonths.get(i) == previousMonth) {
                objs[0] = 0;
            }
            if (alreadyPayMonths.get(i) == leaveMonth) {
                objs[2] = 1;
            }
        }
        if (objs[0] == null) {
            objs[0] = 1;
        }
        if (objs[2] == null) {
            objs[2] = 0;
        }
        String str = String.valueOf(previousMonth);
        objs[1] = str;
        // 是否需要先去交费，交的是哪个月的
        return objs;
    }

    @Override
    public Object[] settlementResults(BigDecimal paySum, BigDecimal billSum, BigDecimal balanceMount, BigDecimal depositMount, BigDecimal otherNeed, BigDecimal fiveTypeFee) {
        // 最终的账单金额 = billSum（退住之前交的入住费及月费） + 退住当月费用
        BigDecimal lastBillSum = billSum.add(fiveTypeFee);
        // 已交和账单的差额
        BigDecimal diffPayAndBill = paySum.subtract(lastBillSum);
        // 退款合计
        BigDecimal refundTal;
        // 欠款合计
        BigDecimal arrearsTal;
        // 计算退款 欠款
        if (diffPayAndBill.compareTo(BigDecimal.ZERO) == 1) {
            refundTal = diffPayAndBill;
            arrearsTal = BigDecimal.ZERO;
        } else if (diffPayAndBill.compareTo(BigDecimal.ZERO) == -1) {
            refundTal = BigDecimal.ZERO;
            arrearsTal = diffPayAndBill;
        } else {
            refundTal = BigDecimal.ZERO;
            arrearsTal = BigDecimal.ZERO;
        }
        // 计算应退、应交 = 退费合计+欠费合计+其他应收+押金合计+预存合计
        BigDecimal totalss = refundTal.add(arrearsTal).add(depositMount).add(balanceMount).subtract(otherNeed);
        // 应交
        BigDecimal shouldAddTal;
        // 应退
        BigDecimal shouldRefundTal;
        // 计算应退、应交
        // 第一个参数大于第二个参数 1
        if (totalss.compareTo(BigDecimal.ZERO) == 1) {
            shouldRefundTal = totalss;
            shouldAddTal = BigDecimal.ZERO;
            // 第一个参数小于第二个参数 -1
        } else if (totalss.compareTo(BigDecimal.ZERO) == -1) {
            shouldRefundTal = BigDecimal.ZERO;
            shouldAddTal = totalss.negate();
            // // 第一个参数等于第二个参数 0
        } else {
            shouldRefundTal = BigDecimal.ZERO;
            shouldAddTal = BigDecimal.ZERO;
        }
        Object[] objs = new Object[5];
        // 四舍五入保留两位/一位小数
        objs[0] = refundTal.setScale(2, BigDecimal.ROUND_HALF_UP);
        objs[1] = arrearsTal.setScale(2, BigDecimal.ROUND_HALF_UP);
        objs[2] = shouldRefundTal.setScale(2, BigDecimal.ROUND_HALF_UP);
        objs[3] = shouldAddTal.setScale(2, BigDecimal.ROUND_HALF_UP);
        objs[4] = fiveTypeFee.setScale(2, BigDecimal.ROUND_HALF_UP);
        return objs;
    }

    @Override
    public List<CheckinfeeVO> getpayRecords(String oldmanId) {
        // 1、根据老人ID 获取押金金额
        CheckinfeeDetailVO checkinfeeDetailVO = checkinfeeDetailRepository.getDepositAndBalance(oldmanId);
        BigDecimal deposts = checkinfeeDetailVO.getDepositMount();
        // 2、获取退住日期，作为参数传入getpayRecords
        CheckInRecordEntity checkInRecordEntity = checkInRecordRepository.getLatestRecordByOldmanId(oldmanId);
        // 退住日期格式化yyyyMM，并转为int，如202012
        String leave1 = new SimpleDateFormat("yyyyMM").format(checkInRecordEntity.getCheckOutTime());
        String leave2 = new SimpleDateFormat("yyyy-MM-dd").format(checkInRecordEntity.getCheckOutTime());
        String leave3 = new SimpleDateFormat("yyyy-MM").format(checkInRecordEntity.getCheckOutTime());
        // 退住年月 202011
        int leaveMonth = Integer.parseInt(leave1);
        // 3、根据老人ID 获取入住、退住期间已交的费用记录 （老人id、退住年月202011、退住当月退还的天数）
        List<CheckinfeeVO> records = baseMapper.getpayRecords(oldmanId, leaveMonth);
        List<CheckinfeeVO> repeatRecords = new ArrayList<CheckinfeeVO>();
        // 4、循环判断 费用记录是入院交费1，则该条记录扣除押金金额
        for (int i = 0; i < records.size(); i++) {
            // yyyy-MM-dd 截取yyyy-MM
            records.get(i).setDatePeriod(records.get(i).getDatePeriod().substring(0, 7));
            // 类型为1：入住交费，去掉押金明细
            if (records.get(i).getCategory() == 1) {
                records.get(i).setActualfee(records.get(i).getActualfee().subtract(deposts));
            }
            // 月费对应时间段跟 退住时间段（yy-mm年月） 对比，是则 将记录添加到repeatRecords， 移除records记录
            if (records.get(i).getDatePeriod().equals(leave3)) {
                repeatRecords.add(records.get(i));
                records.remove(i);
                i--;
            }
        }
        // size = 2,说明有两条退住月，月费记录重复，已交月和退住月（不满一个月，重新计算）重复，移除掉一个记录
        if (repeatRecords.size() == 2) {
            // 计算重复月的差值，退还金额
            BigDecimal A = repeatRecords.get(0).getReducedfee().add(repeatRecords.get(0).getActualfee());
            BigDecimal B = repeatRecords.get(1).getReducedfee().add(repeatRecords.get(1).getActualfee());
            BigDecimal diff = null;
            if (A.compareTo(B) == 1) {
                diff = A.subtract(B).setScale(2, BigDecimal.ROUND_HALF_UP);
            } else {
                diff = B.subtract(A).setScale(2, BigDecimal.ROUND_HALF_UP);
            }
            // 判断移除哪个重复记录
            for (int b = 0; b < repeatRecords.size(); b++) {
                if (repeatRecords.get(b).getDatePeriod() == leave2) {
                    repeatRecords.remove(b);
                }
            }
            repeatRecords.get(0).setDescribes(repeatRecords.get(0).getDescribes() + "  退还" + diff);
        }
        records.add(repeatRecords.get(0));
        return records;
    }

}